package br.com.toscano.contpedido.business;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

import javax.inject.Inject;

import br.com.toscano.contpedido.domain.Pedido;
import br.com.toscano.contpedido.domain.PedidoProduto;
import br.com.toscano.contpedido.domain.Produto;
import br.com.toscano.contpedido.domain.ProdutoProduto;
import br.com.toscano.contpedido.domain.Recebimento;
import br.com.toscano.contpedido.domain.StatusPedido;
import br.com.toscano.contpedido.otd.PedidoConsolidado;
import br.com.toscano.contpedido.otd.ProducaoOTD;
import br.com.toscano.contpedido.otd.ProdutoOTD;
import br.com.toscano.contpedido.otd.UsuarioVendedorOTD;
import br.com.toscano.contpedido.persistence.PedidoDAO;
import br.com.toscano.contpedido.persistence.PedidoProdutoDAO;
import br.com.toscano.contpedido.persistence.RecebimentoDAO;
import br.gov.frameworkdemoiselle.stereotype.BusinessController;
import br.gov.frameworkdemoiselle.template.DelegateCrud;
import br.gov.frameworkdemoiselle.transaction.Transactional;

@BusinessController
public class PedidoBC extends DelegateCrud<Pedido, Long, PedidoDAO> {
	
	private static final long serialVersionUID = 1L;

	public Pedido consultarUltimoPedidos(Long idCliente) {
		return this.getDelegate().consultarUltimoPedidos(idCliente);
	}

	@Inject
	private RecebimentoDAO recebimentoDAO;

	@Inject
	private PedidoProdutoDAO pedidoProdutoDAO;

	public PedidoConsolidado consultarPedidosConsolidado(Long idPedido, Long idCliente, Long idUsuario, Long idStatusPedido, Date dataCadastroInicial, Date dataCadastroFinal, Date dataEntregaInicial, Date dataEntregaFinal) {
		
		Integer quantidadeTotalPedidos = 0;
		Integer quantidadeCancelados = 0;
		Integer quantidadeEntregue = 0;
		Integer quantidadePagos = 0;
		Integer quantidadeConferidos = 0;

		BigDecimal valorTotalPedidos = BigDecimal.ZERO;
		BigDecimal valorCancelados = BigDecimal.ZERO;
		BigDecimal valorEntregue = BigDecimal.ZERO;
		BigDecimal valorPagos = BigDecimal.ZERO;
		BigDecimal valorConferidos = BigDecimal.ZERO;

		List<Pedido> lista = consultarPedidos(null, idPedido, idCliente, idUsuario, idStatusPedido, null, dataCadastroInicial, dataCadastroFinal, dataEntregaInicial, dataEntregaFinal, null, null);
		for (Pedido pedido : lista) {
			valorTotalPedidos = valorTotalPedidos.add(pedido.getValorTotalPedido());
			quantidadeTotalPedidos = quantidadeTotalPedidos + 1;

		if (pedido.getStatusPedido().getId().equals(StatusPedido.CONFERIDO)) {

			valorConferidos = valorPagos.add(pedido.getValorTotalPedido());
			quantidadeConferidos = quantidadePagos + 1;

			valorPagos = valorPagos.add(pedido.getValorTotalPedido());
			quantidadePagos = quantidadePagos + 1;

			valorEntregue = valorEntregue.add(pedido.getValorTotalPedido());
			quantidadeEntregue = quantidadeEntregue + 1;

		} else if (pedido.getStatusPedido().getId().equals(StatusPedido.PAGO)) {
				valorPagos = valorPagos.add(pedido.getValorTotalPedido());
				quantidadePagos = quantidadePagos + 1;

				valorEntregue = valorEntregue.add(pedido.getValorTotalPedido());
				quantidadeEntregue = quantidadeEntregue + 1;

			} else if (pedido.getStatusPedido().getId().equals(StatusPedido.ENTREGUE)) {

				valorEntregue = valorEntregue.add(pedido.getValorTotalPedido());
				quantidadeEntregue = quantidadeEntregue + 1;

			} else if (pedido.getStatusPedido().getId().equals(StatusPedido.CANCELADO)) {

				valorCancelados = valorCancelados.add(pedido.getValorTotalPedido());
				quantidadeCancelados = quantidadeCancelados + 1;
			} 
			
			
		}
		
		PedidoConsolidado retorno = new PedidoConsolidado(quantidadeTotalPedidos,
				quantidadeCancelados, quantidadeEntregue,
				quantidadePagos, quantidadeConferidos, valorTotalPedidos,
				valorCancelados, valorEntregue,
				valorPagos, valorConferidos);
		
		return retorno;		
	}
	public List<Pedido> consultarPedidos(Boolean soExibePedidosAgendados, Long idPedido, Long idCliente, Long idUsuario, Long idStatusPedido, Boolean produzido, Date dataCadastroInicial, Date dataCadastroFinal, Date dataEntregaInicial, Date dataEntregaFinal, Boolean exibirCancelados, Byte tipoPagamento) {
		List<Pedido> pedidos =  this.getDelegate().consultarPedidos(soExibePedidosAgendados,idPedido, idCliente, idUsuario, idStatusPedido, produzido, dataCadastroInicial, dataCadastroFinal, dataEntregaInicial, dataEntregaFinal, exibirCancelados, tipoPagamento);
		
		for (Pedido p : pedidos) {
			for (PedidoProduto pp : p.getListaPedidoProduto()) {
				pp.getProduto().getDescricao();
				pp.getProduto().getValor();
				pp.getQuantidade();
				
			}
		}
		
		return pedidos;
	}

	public void registrarPagamento(Long idPedido) {
		this.getDelegate().registrarPagamento(idPedido);
	}
	

	public void registrarConferido(Long idPedido) {
		this.getDelegate().registrarConferido(idPedido);
	}
	
	public void registrarCancelamento(Long idPedido) {
		this.getDelegate().registrarCancelamento(idPedido);
	}
	
	public void registrarEngregue(Long idPedido) {
		this.getDelegate().registrarEngregue(idPedido);
	}
	
	public void registrarProducao(Long idPedido) {
		this.getDelegate().registrarProducao(idPedido);
	}
	
	public void cancelarPagamento(Long idRecebimento) {
		Recebimento recebimento = recebimentoDAO.load(idRecebimento);
		for(Pedido pedido : recebimento.getListaPedido()) {
			StatusPedido sp = new StatusPedido();
			sp.setId(StatusPedido.ENTREGUE);
			pedido.setStatusPedido(sp);
			this.update(pedido);
		}
	}
	
	@Override
	@Transactional
	public void delete(Long id) {
		this.pedidoProdutoDAO.removerPedidoProduto(new ArrayList<Long>(), id);
		this.getDelegate().delete(id);
	}

	@Override
	@Transactional
	public void delete(List<Long> ids) {
		// TODO Auto-generated method stub
		for (Long id : ids) {
			this.delete(id);
		}
	}
	
	public List<UsuarioVendedorOTD> gerarUsuarioVendedor(Date dataInicial, Date dataFinal){
		List<UsuarioVendedorOTD> retorno = new ArrayList<UsuarioVendedorOTD>();
		
		List<Pedido> listaPedido = this.getDelegate().consultarPedidos(null, null, null, null, null, null, null, null, dataInicial, dataFinal, false, null);
		for (Pedido pedido:listaPedido) {
			
			UsuarioVendedorOTD novo = null;
			for (UsuarioVendedorOTD cadastrado : retorno) {
				if (cadastrado.getIdUsuario().equals(pedido.getUsuario().getId())) {
					novo = cadastrado;
					break;
				}
			}
			
			if (novo == null) {
				novo = new UsuarioVendedorOTD();
				retorno.add(novo);
			}
			
			novo.setIdUsuario(pedido.getUsuario().getId());
			novo.setNome(pedido.getUsuario().getNome());
			novo.setQuantidade( novo.getQuantidade().add(BigDecimal.ONE) );
			novo.setValorTotal(novo.getValorTotal().add(pedido.getValorTotalPedido()));
		}
		return retorno;
	}
	
	
	public List<ProducaoOTD> gerarListagemProducao(Long idLocalProducao) {
		List<ProducaoOTD> retorno = new ArrayList<ProducaoOTD>();
		
		List<Pedido> pedidos = consultarPedidos(true, null, null, null, null, false, null, null, null, null, false, null);
		
		for(Pedido pedido : pedidos) {
			ProducaoOTD producao = gerarProduto(pedido, idLocalProducao);
			if (producao != null) {
				retorno.add(producao);	
			}
		}

		Collections.sort(retorno, new Comparator<ProducaoOTD>() {
			  public int compare(ProducaoOTD p1, ProducaoOTD p2) {

				  String descricao1 = "";
				  String descricao2 = "";
				  if (p1.getDataProducao() != null ) {
					  Date data = p1.getDataProducao();
					  if (p1.getHoraProducao() != null) {
						  Calendar cal = Calendar.getInstance();
						  cal.setTime(data);
						  cal.set(Calendar.HOUR, p1.getHoraProducao());
						  data = cal.getTime();
					  }
					  if (p1.getMinutoProducao() != null) {
						  Calendar cal = Calendar.getInstance();
						  cal.setTime(data);
						  cal.set(Calendar.MINUTE, p1.getMinutoProducao());
						  data = cal.getTime();
					  }
					  descricao1 = "a" + data.getTime();
				  } else {
					  descricao1 = "z" + p1.getDataEntrega();
				  }
				  
				  if (p2.getDataProducao() != null ) {
					  Date data = p2.getDataProducao();
					  if (p2.getHoraProducao() != null) {
						  Calendar cal = Calendar.getInstance();
						  cal.setTime(data);
						  cal.set(Calendar.HOUR, p2.getHoraProducao());
						  data = cal.getTime();
					  }
					  if (p2.getMinutoProducao() != null) {
						  Calendar cal = Calendar.getInstance();
						  cal.setTime(data);
						  cal.set(Calendar.MINUTE, p2.getMinutoProducao());
						  data = cal.getTime();
					  }
					  descricao2 = "a" + data.getTime();
				  } else {
					  descricao2 = "z" + p2.getDataEntrega();
				  }
				  
			      return descricao1.compareTo(descricao2);
			  }
			});
		
		return retorno;
	}
	
	private ProducaoOTD gerarProduto(Pedido pedido, Long idLocalProducao) {
		ProducaoOTD retorno = new ProducaoOTD();

		retorno.setIdPedido(pedido.getId());
		retorno.setIdCliente(pedido.getCliente().getId());
		retorno.setNomeCliente(pedido.getCliente().getNome());
		retorno.setDataProducao(pedido.getDataProducao());
		retorno.setHoraProducao(pedido.getHoraProducao());
		retorno.setMinutoProducao(pedido.getMinutoProducao());
		retorno.setDataEntrega(pedido.getDataEntrega());
		retorno.setHoraEntrega(pedido.getHora());
		retorno.setMinutoEntrega(pedido.getMinuto());
		retorno.setObservacao(pedido.getObservacao());

		boolean temProdutoParaEsseLocal = false;
		for(PedidoProduto pp : pedido.getListaPedidoProduto()) {
			temProdutoParaEsseLocal = adicionarProduto(idLocalProducao, retorno, temProdutoParaEsseLocal, pp.getProduto(), pp.getQuantidade(), pp.getValorTotalItem());
		}
		if (idLocalProducao != null && !temProdutoParaEsseLocal) {
			return null;
		}
		return retorno; 
	}

	public boolean adicionarProduto(Long idLocalProducao, ProducaoOTD retorno, boolean temProdutoParaEsseLocal, Produto p, BigDecimal quantidade, BigDecimal valor) {
		//@@ todo verificar os subprodutos
		ProdutoOTD produto = new ProdutoOTD();
		produto.setIdPedido(p.getId());
		produto.setDescricaoProduto(p.getDescricao());
		produto.setQuantidade(quantidade); 
		produto.setValorTotal(valor);
		produto.setUnidadeMedida(p.getUnidadeMedida().getDescricao());
		if (idLocalProducao != null) {
			if (p.getLocalProducao()  != null && p.getLocalProducao().getId().equals(idLocalProducao)) {
				temProdutoParaEsseLocal = true;
				produto.setIdLocalProducao(p.getLocalProducao().getId());
				produto.setDescricaoLocalProducao(p.getLocalProducao().getDescricao());
				retorno.getListaProdutoOTDs().add(produto);
			}
		} else {
			retorno.getListaProdutoOTDs().add(produto);
		}

		if (p.getListaProdutoProdutos() != null) {
			for(ProdutoProduto pp : p.getListaProdutoProdutos()) {
				boolean temProdutoParaEsseLocalNosSubs = adicionarProduto(idLocalProducao, retorno, temProdutoParaEsseLocal, pp.getProdutoFilho(), quantidade.multiply(new BigDecimal(pp.getQuantidade())), quantidade.multiply(new BigDecimal(pp.getQuantidade())).multiply(pp.getProdutoFilho().getValor()));
				temProdutoParaEsseLocal = temProdutoParaEsseLocal || temProdutoParaEsseLocalNosSubs;
			}
		}
		return temProdutoParaEsseLocal;
	}

	@Override
	public Pedido insert(Pedido bean) {
		bean = this.getDelegate().insert(bean);
		adicionarPedidoProduto(bean);
		return bean;
	}
	
	private void adicionarPedidoProduto(Pedido bean){
		for (PedidoProduto pp : bean.getListaPedidoProduto()) {
			pp.setPedido(bean);
			this.pedidoProdutoDAO.insert(pp);
		}
	}

	@Override
	public Pedido update(Pedido bean) {
		this.pedidoProdutoDAO.removerPedidoProduto(new ArrayList<Long>(), bean.getId());
		adicionarPedidoProduto(bean);
		bean = this.getDelegate().update(bean);
		return bean;
	}
}
